Author

Diego Cruz Aguilar

Published

August 11, 2024

Modified

December 2, 2024

1 Esquema propuesto

Esquema propuesto

2 Librerías

Code
import time
import numpy as np
import pandas as pd
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import plotly.express as px
from itables import show
from utils.mimic_load import load_csv, segment_signal_by_label
from utils.style import catppuccin

3 Variables globales

Code
RANDOM_SEED = int(time.time())
USER_SELECT = 1
SEGMENT_SIZE = 3750  # Equivalente a 30s de muestras
FS = 1250
FOLDER_PATH = "./dataset/mimic_perform_af_csv"
theme = catppuccin["mocha"]

4 Carga de datos

Code
final_df = load_csv(FOLDER_PATH, USER_SELECT)
filtered_df = final_df[final_df['label'] == 0]

5 Conocer los datos

5.1 Ver los primeros datos y sus cabeceras

Code
final_df.head()
Time PPG ECG resp numb_user label
0 0.000 0.537634 0.425781 -0.029340 1 0
1 0.008 0.534702 0.404297 -0.036675 1 0
2 0.016 0.531769 0.400391 -0.044010 1 0
3 0.024 0.528837 0.400391 -0.053790 1 0
4 0.032 0.524927 0.419922 -0.061125 1 0

5.2 Información de los datos

Code
final_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2100014 entries, 0 to 2100013
Data columns (total 6 columns):
 #   Column     Dtype  
---  ------     -----  
 0   Time       float64
 1   PPG        float64
 2   ECG        float64
 3   resp       float64
 4   numb_user  int64  
 5   label      int64  
dtypes: float64(4), int64(2)
memory usage: 96.1 MB

5.3 Descripción de los datos

Code
final_df.describe()
Time PPG ECG resp numb_user label
count 2.100014e+06 2.100014e+06 2.100014e+06 2.100014e+06 2.100014e+06 2.100014e+06
mean 6.000000e+02 1.193070e+00 3.920216e-01 2.226942e-01 1.057143e+01 9.285714e-01
std 3.464126e+02 7.767317e-01 2.349270e-01 4.319208e-01 5.827452e+00 2.575394e-01
min 0.000000e+00 0.000000e+00 -5.019608e-01 -1.846506e+00 1.000000e+00 0.000000e+00
25% 3.000000e+02 4.633431e-01 2.346041e-01 -4.156479e-02 6.000000e+00 1.000000e+00
50% 6.000000e+02 8.064516e-01 3.847656e-01 2.200000e-01 1.150000e+01 1.000000e+00
75% 9.000000e+02 1.893451e+00 5.195312e-01 4.643077e-01 1.600000e+01 1.000000e+00
max 1.200000e+03 4.001955e+00 1.503922e+00 2.844215e+00 1.900000e+01 1.000000e+00

5.4 Tamaño de los datos

Code
final_df.shape
(2100014, 6)

5.5 Visualizar su distribución

Code
columns_to_plot = ["PPG", "resp"]
plot_df = filtered_df[columns_to_plot]

fig = px.histogram(
    plot_df.melt(var_name="Variable", value_name="Valor"),
    x="Valor",
    color="Variable",
    facet_row="Variable",  # Usa facet_row para los gráficos en filas
    title="Distribuciones de las Variables Seleccionadas",
    nbins=50,
    color_discrete_map={
        "PPG": theme["red"],  # Color red para PPG
        "resp": theme["blue"]  # Color blue para resp
    }
)
fig.show()

5.6 Detección de valores atípicos

Code
fig = go.Figure()

fig.add_trace(go.Box(
    y=filtered_df['PPG'],
    name='PPG',
    marker=dict(color=theme["red"])
))

fig.add_trace(go.Box(
    y=filtered_df['resp'],
    name='Resp',
    marker=dict(color=theme["blue"])
))

fig.update_layout(
    title="Boxplots para Identificación de Valores Atípicos",
    xaxis_title="Variables",
    yaxis_title="Valores",
    template="plotly_white"
)

fig.show()

5.7 Análisis de correlación

Code
ppg_color = theme["red"]
resp_color = theme["blue"]

fig = px.scatter(
    filtered_df,
    x='PPG',
    y='resp',
    title='Scatter Plot: PPG vs resp',
    labels={'x': 'PPG', 'y': 'Resp'}
)

fig.update_traces(marker=dict(color=ppg_color))

fig.show()

5.8 Reconstruir la señal(raw)

Code
def plot_raw_analysis(x_data, y_data, color):
    fig = go.Figure()

    fig.add_trace(go.Scatter(
        x=x_data,
        y=y_data,
        mode='lines',
        line=dict(color=color)
    ))

    fig.show()

plot_raw_analysis(
    x_data=filtered_df["Time"],
    y_data=filtered_df["PPG"],
    color=theme["red"]
)

plot_raw_analysis(
    x_data=filtered_df["Time"],
    y_data=filtered_df["resp"],
    color=theme["blue"]
)
(a) PPG
(b) Resp
Figure 1: Reconstrucción de las señales de uno de los usuarios

5.9 Análisis de frecuencias

Code
# Frecuencia de muestreo

def process_signal(signal, sampling_rate, freq_range):
    # Intervalo de muestreo
    d = 1 / sampling_rate

    # Transformada de Fourier
    freq_transform = np.fft.fft(signal)
    frequencies = np.fft.fftfreq(len(freq_transform), d=d)

    # Filtrar frecuencias positivas
    positive_freqs = frequencies[:len(frequencies) // 2]
    positive_amplitudes = np.abs(freq_transform)[:len(freq_transform) // 2]

    # Aplicar máscara para el rango de interés
    freq_mask = (positive_freqs > freq_range[0]) & (positive_freqs < freq_range[1])

    return positive_freqs[freq_mask], positive_amplitudes[freq_mask]

fs = 125  # Hz

ppg_signal = filtered_df['PPG'].values
resp_signal = filtered_df['resp'].values

ppg_result = process_signal(ppg_signal, fs, (0.5, 3))  # Rango PPG
resp_result = process_signal(resp_signal, fs, (0.1, 0.5))  # Rango RESP

positive_ppg_freqs, positive_ppg_amplitudes = ppg_result
positive_resp_freqs, positive_resp_amplitudes = resp_result

def plot_frequency_analysis(x_data, y_data, x_axis_title, y_axis_title, x_range, color):
    fig = go.Figure()

    fig.add_trace(go.Scatter(
        x=x_data,
        y=y_data,
        mode='lines',
        line=dict(color=color)
    ))

    fig.update_layout(
        xaxis_title=x_axis_title,
        yaxis_title=y_axis_title,
        template="plotly_white"
    )

    fig.update_xaxes(range=x_range)

    fig.show()

plot_frequency_analysis(
    x_data=positive_ppg_freqs,
    y_data=positive_ppg_amplitudes,
    x_axis_title="Frecuencia (Hz)",
    y_axis_title="Amplitud",
    x_range=[0.5, 3],
    color=theme["red"]
)


plot_frequency_analysis(
    x_data=positive_resp_freqs,
    y_data=positive_resp_amplitudes,
    x_axis_title="Frecuencia (Hz)",
    y_axis_title="Amplitud",
    x_range=[0.1, 0.5],
    color=theme["blue"]
)
(a) PPG
(b) Resp
Figure 2: Frecuencia

5.10 Comparativa de frecuencias entre dos usuarios

Code
# Frecuencia de muestreo

user2_df = final_df[final_df['numb_user'] == 2]
ppg_signal2 = user2_df['PPG'].values

ppg_result2 = process_signal(ppg_signal2, fs, (0.5, 3))  # Rango PPG

positive_ppg_freqs2, positive_ppg_amplitudes2 = ppg_result2

plot_frequency_analysis(
    x_data=positive_ppg_freqs,
    y_data=positive_ppg_amplitudes,
    x_axis_title="Frecuencia (Hz)",
    y_axis_title="Amplitud",
    x_range=[0.5, 3],
    color=theme["red"]
)

plot_frequency_analysis(
    x_data=positive_ppg_freqs2,
    y_data=positive_ppg_amplitudes2,
    x_axis_title="Frecuencia (Hz)",
    y_axis_title="Amplitud",
    x_range=[0.5, 3],
    color=theme["pink"]
)
(a) User 1
(b) User 2
Figure 3: PPG Frequency

6 Experimentos

6.1 Segmentar los datos

Code
segments_ppg, segments_resp, segment_labels, user_ids = segment_signal_by_label(
    final_df, SEGMENT_SIZE
)

middle_segment = len(segments_ppg) // 2
segments_ppg[middle_segment], segments_resp[middle_segment]
(array([2.15249267, 2.22091887, 2.285435  , ..., 1.94330401, 2.08797654,
        2.22385142]),
 array([-0.02626756, -0.02565669, -0.02504582, ..., -0.06108735,
        -0.06047648, -0.05986561]))

6.2 Obtener la fingerprint de la unión de las señales(PPG y respiración)

6.2.1 Algoritmo ExtractWaveletFeatures

Es un algoritmo que extrae características estadísticas a partir de señales utilizando la descomposición wavelet. A partir de un segmento de señal, este método aplica una transformada wavelet discreta, descomponiéndolo en coeficientes correspondientes a diferentes niveles de frecuencia. Para cada conjunto de coeficientes, calcula una serie de elementos estadísticos. Todos las formas de extracción de características probadas se basan en este algoritmo.

\begin{algorithm} \caption{Extract Wavelet Statistics Features} \begin{algorithmic} \Procedure{ExtractWaveletFeatures}{$segment, wavelet, level$} \State $coeffs \gets $ \Call{WaveletDecomposition}{$segment, wavelet, level$} \State $segment\_features \gets []$ \For{$coeff \in coeffs$} \State $mean \gets $ \Call{Mean}{$coeff$} \State $std \gets $ \Call{StandardDeviation}{$coeff$} \State $kurt \gets $ \Call{Kurtosis}{$coeff$} \State $skewness \gets $ \Call{Skewness}{$coeff$} \State $max\_val \gets $ \Call{Max}{$coeff$} \State $min\_val \gets $ \Call{Min}{$coeff$} \State $energy \gets $ \Call{SumOfSquares}{$coeff$} \State $entropy \gets $ \Call{ShannonEntropy}{$coeff$} \State \Call{Append}{$segment\_features, [mean, std, kurt, skewness, max\_val, min\_val, energy, entropy]$} \EndFor \State \Return $segment\_features$ \EndProcedure \end{algorithmic} \end{algorithm}

6.2.2 Algoritmo ComputeCrossDynamics

Extrae características dinámicas cruzadas entre dos señales fisiológicas (Para estos experimentos PPG y Respiración) mediante análisis de la envolvente instantánea y relaciones estructurales. Utiliza la transformada de Hilbert para obtener las envolventes de amplitud de ambas señales y calcula la correlación cruzada normalizada, caracterizando su sincronización temporal. Además, aplica descomposición en valores singulares (SVD) a una matriz combinada de las envolventes para analizar la distribución de energía en sus componentes principales. A partir de estas representaciones, extrae métricas estadísticas.

\begin{algorithm} \caption{Compute Cross Dynamics Features (HilbertTransform)} \begin{algorithmic} \Procedure{ComputeCrossDynamics}{$ppg\_segment, resp\_segment$} \State $hilbert\_ppg \gets$ \Call{AbsoluteValue}{\Call{HilbertTransform}{$ppg\_segment$}} \State $hilbert\_resp \gets$ \Call{AbsoluteValue}{\Call{HilbertTransform}{$resp\_segment$}} \State $cross\_corr \gets$ \Call{Correlate}{$hilbert\_ppg, hilbert\_resp$} \State $norm\_cross\_corr \gets cross\_corr /$ \Call{Max}{\Call{AbsoluteValue}{$cross\_corr$}} \State $combined\_matrix \gets$ \Call{Stack}{$[hilbert\_ppg, hilbert\_resp]$} \State $U, singular\_values, V \gets$ \Call{SVD}{$combined\_matrix$} \State $features \gets []$ \State \Call{Append}{$features, $ \Call{Mean}{$norm\_cross\_corr$}} \State \Call{Append}{$features, $ \Call{StandardDeviation}{$norm\_cross\_corr$}} \State \Call{Append}{$features, $ \Call{Kurtosis}{$norm\_cross\_corr$}} \State \Call{Append}{$features, $ \Call{Skewness}{$norm\_cross\_corr$}} \State \Call{Append}{$features, singular\_values[0] /$ \Call{Sum}{$singular\_values$}} \State \Call{Append}{$features, $ \Call{ShannonEntropy}{$singular\_values$}} \State \Return $features$ \EndProcedure \end{algorithmic} \end{algorithm}

6.2.3 Extracción de características

Para la extracción de características, se realizaron una serie de pruebas para medir el desempeño de diferentes métodos de extracción de características. Estas pruebas dieron como resultado 6 posibles combinaciones de métodos de extracción, en la sección de resultados se detallarán los resultados de cada una de ellas.

6.2.3.1 Algoritmos para extracción de características

Se presentan los algoritmos con sus respectivas etiquetas acortadas, con fines de una mejor presentación de los algoritmos en las gráficas.

6.2.3.1.1 Algoritmo 1: m
\begin{algorithm} \caption{Extract Wavelet Statistics Features from PPG and Respiratory Signals} \begin{algorithmic} \Procedure{MultiplyFeatures}{$ppg\_segment, resp\_segment$} \State $n \gets \text{length}(ppg\_segment)$ \State $product\_segment \gets \text{Array of length } n$ \For{$i \gets 1$ \textbf{to} $n$} \State $product\_segment[i] \gets ppg\_segment[i] \times resp\_segment[i]$ \EndFor \State \Return \Call{ExtractWaveletFeatures}{$product\_segment, db4, 3$} \EndProcedure \end{algorithmic} \end{algorithm}
6.2.3.1.2 Algoritmo 2: mc
\begin{algorithm} \caption{Multiply and Correlation Features Extraction} \begin{algorithmic} \Procedure{MultiplyCorrFeatures}{$ppg\_segment, resp\_segment$} \State $cross\_corr \gets$ \Call{CrossCorrelation}{$ppg\_segment, resp\_segment, mode="full"$} \State $cross\_corr\_stats \gets []$ \State \Call{Append}{cross\_corr\_stats, \Call{Max}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{Min}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{Mean}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{StandardDeviation}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{SumOfSquares}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{Kurtosis}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{Skewness}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{ShannonEntropy}{$cross\_corr$}} \State $n \gets \text{length}(ppg\_segment)$ \State $product\_segment \gets \text{Array of length } n$ \For{$i \gets 1$ \textbf{to} $n$} \State $product\_segment[i] \gets ppg\_segment[i] \times resp\_segment[i]$ \EndFor \State $wv_stats \gets $ \Call{ExtractWaveletFeatures}{$product\_segment, db4, 3$} \State $combined\_features \gets []$ \State \Call{Append}{$combined\_features, [cross\_corr\_stats, wv\_stats]$} \State \Return $combined\_features$ \EndProcedure \end{algorithmic} \end{algorithm}

6.2.3.2 Algoritmo 3: mcd

\begin{algorithm} \caption{Multiply Cross Dynamics Features Extraction} \begin{algorithmic} \Procedure{MultiplyCrossDynamicsFeatures}{$ppg\_segment, resp\_segment$} \State $cross\_dynamics\_features \gets $ \Call{ComputeCrossDynamics}{$ppg\_segment, resp\_segment$} \State $wv_stats \gets $ \Call{ExtractWaveletFeatures}{$product\_segment, db4, 3$} \State $combined\_features \gets []$ \State \Call{Append}{$combined\_features, [cross\_corr\_stats, wv\_stats]$} \State \Return $combined\_features$ \EndProcedure \end{algorithmic} \end{algorithm}
6.2.3.2.1 Algoritmo 4: cs
\begin{algorithm} \caption{Cross Dynamics Features Extraction} \begin{algorithmic} \Procedure{CombinedCrossDynamicsFeatures}{$ppg\_segment, resp\_segment$} \State $features\_ppg \gets$ \Call{ExtractWaveletFeatures}{$ppg\_segment, wavelet="db4"$} \State $features\_resp \gets$ \Call{ExtractWaveletFeatures}{$resp\_segment, wavelet="bior3.7"$} \State $cross\_dynamics\_features \gets$ \Call{ComputeCrossDynamics}{$ppg\_segment, resp\_segment$} \State $combined\_features \gets []$ \State \Call{Append}{$combined\_features, [features\_ppg, features\_resp, cross\_dynamics\_features]$} \State \Return $combined\_features$ \EndProcedure \end{algorithmic} \end{algorithm}
6.2.3.2.2 Algoritmo 5: cs
\begin{algorithm} \caption{Cross Stats Features Extraction} \begin{algorithmic} \Procedure{CrossStatsFeatures}{$ppg\_segment, resp\_segment$} \State $features\_ppg \gets$ \Call{ExtractWaveletFeatures}{$ppg\_segment, wavelet="db4"$} \State $features\_resp \gets$ \Call{ExtractWaveletFeatures}{$resp\_segment, wavelet="bior3.7"$} \State $cross\_corr \gets$ \Call{CrossCorrelation}{$ppg\_segment, resp\_segment, mode="full"$} \State $cross\_corr\_stats \gets []$ \State \Call{Append}{cross\_corr\_stats, \Call{Max}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{Min}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{Mean}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{StandardDeviation}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{SumOfSquares}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{Kurtosis}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{Skewness}{$cross\_corr$}} \State \Call{Append}{cross\_corr\_stats, \Call{ShannonEntropy}{$cross\_corr$}} \State $combined\_features \gets []$ \State \Call{Append}{$combined\_features, [features\_ppg, features\_resp, cross\_corr]$} \State \Return $combined\_features$ \EndProcedure \end{algorithmic} \end{algorithm}

6.2.3.3 Algoritmo 6: cdm, cd

Entre el algoritmo cdm y el cd, el cdm contiene 3 características mas que no contiene cd.

\begin{algorithm} \caption{Cross Dinamics More Features Extraction} \begin{algorithmic} \Procedure{CrossDynamicsMoreFeatures}{$ppg\_segment, resp\_segment$} \State $amplitude\_ppg \gets$ \Call{ExtractAplitude}{$ppg\_segment$} \State $heart\_rate\_ppg \gets$ \Call{ExtractHeartRate}{$ppg\_segment$} \State $breath\_rate\_resp \gets$ \Call{ExtractBreathRate}{$resp\_segment$} \State $features\_ppg \gets$ \Call{ExtractWaveletFeatures}{$ppg\_segment, wavelet="db4"$} \State $features\_resp \gets$ \Call{ExtractWaveletFeatures}{$resp\_segment, wavelet="bior3.7"$} \State $cross\_dynamics\_features \gets$ \Call{ComputeCrossDynamics}{$ppg\_segment, resp\_segment$} \State $combined\_features \gets []$ \State \Call{Append}{$combined\_features, [features\_ppg, features\_resp, cross\_dynamics\_features, amplitude\_ppg, heart\_rate\_ppg, breath\_rate\_resp]$} \State \Return $combined\_features$ \EndProcedure \end{algorithmic} \end{algorithm}

6.2.4 Extracción de características con el mejor algoritmo

Code
from utils.extact_features import compute_features_parallel
combined_features = compute_features_parallel(segments_ppg, segments_resp, FS)
combined_features[0], len(combined_features)
(array([ 1.36472759e+00,  2.70545818e-01, -9.22594233e-01,  1.25886370e-01,
         1.98144061e+00,  8.24251787e-01,  9.17510633e+02,  6.14145276e+00,
        -1.80968071e-04,  8.35478571e-03,  9.32966678e-01,  6.03824831e-01,
         2.91382149e-02, -2.04860227e-02,  3.31018818e-02,  5.75799279e+00,
        -7.45894319e-06,  1.42086863e-03,  1.42183565e+01,  6.53088052e-01,
         1.40151520e-02, -8.57327975e-03,  1.90182574e-03,  6.43393434e+00,
        -6.37711225e-06,  3.73592271e-04,  1.74541833e+00, -2.17755297e-01,
         1.66478462e-03, -2.55753171e-03,  2.62191060e-04,  7.24331034e+00,
         6.19581879e-02,  7.24997586e-01, -4.86277977e-01,  9.34663499e-01,
         1.90172755e+00, -9.71714161e-01,  2.54670412e+02,  5.96627214e+00,
        -9.52988670e-05,  4.39476325e-03,  1.85439603e+01,  1.20304746e-01,
         3.27447597e-02, -3.27447597e-02,  9.29437547e-03,  5.61846673e+00,
        -8.06641631e-05,  1.23739345e-03,  5.59740223e-01, -4.65897730e-02,
         5.74069967e-03, -5.74069967e-03,  1.45769151e-03,  6.54296586e+00,
         8.63515085e-05,  5.93021050e-04, -5.57631423e-01,  1.88280548e-02,
         1.72886744e-03, -1.72886744e-03,  6.75883693e-04,  7.10000314e+00,
         4.96853702e-01,  2.83236494e-01, -1.12771811e+00, -3.25932656e-04,
         8.32995690e-01,  4.51104214e-01,  6.14738564e-01,  9.89010989e+02,
         3.40136054e+02]),
 560)

6.3 Comparar características combinadas de un mismo usuario

Code
def get_features_for_user(combined_features, user_ids, target_user_id):
    return [feature for feature, user_id in zip(combined_features, user_ids) if user_id == target_user_id]

target_user_id = 1
user_1_features = get_features_for_user(combined_features, user_ids, target_user_id)

def compare_plot(data, x_label, y_label, color):
    fig = go.Figure()
    fig.add_trace(go.Scatter(
        x=list(range(len(data))),
        y=data,
        mode='lines+markers',
        line=dict(color=color),
        marker=dict(size=7, opacity=0.7),
    ))
    fig.update_layout(
        xaxis_title=x_label,
        yaxis_title=y_label,
        xaxis=dict(tickangle=45),
        template='plotly_white'
    )
    fig.show()

compare_plot(
    data=user_1_features[0],
    x_label="Index",
    y_label="Value",
    color=theme["peach"],
)

compare_plot(
    data=user_1_features[-1],
    x_label="Index",
    y_label="Value",
    color=theme["yellow"],
)
(a) User 1 - first segment
(b) User 1 - last segment
Figure 4: Fingerprint of the union of the features

6.4 Comparar caracteristicas combinadas de dos usuarios diferentes

Code
compare_plot(
    data=combined_features[0],
    x_label="Index",
    y_label="Value",
    color=theme["green"],
)

compare_plot(
    data=combined_features[-1],
    x_label="Index",
    y_label="Value",
    color=theme["sapphire"],
)
(a) User 1 - first segment
(b) User 2 - first segment
Figure 5: Fingerprint of the union of the features

6.5 Seleccionar clasificadores

Code
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression

# from sklearn.ensemble import GradientBoostingClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier

classifiers = {
    "Random Forest": RandomForestClassifier(n_estimators=100, random_state=RANDOM_SEED),
    "Logistic Regression": LogisticRegression(max_iter=1000, random_state=RANDOM_SEED),
    "KNN": KNeighborsClassifier(),
    "SVM": SVC(random_state=RANDOM_SEED),
    "Decision Tree": DecisionTreeClassifier(),
    "Naive Bayes Gaussiano": GaussianNB(),
}

6.6 Probar clasificadores


Probando clasificador: Random Forest

Probando clasificador: Logistic Regression

Probando clasificador: KNN

Probando clasificador: SVM

Probando clasificador: Decision Tree

Probando clasificador: Naive Bayes Gaussiano

7 Resultados

7.1 Comparativa de los resultados(distintas formas de combinar y extraer las características de las señales)

Code
df_ranking = pd.read_csv("./ranking_short.csv")
df_best = df_ranking.sort_values(by='Cross-Validation Accuracy', ascending=False)
best_combination_per_feature = df_best.loc[df_best.groupby('Feature Extraction')['Cross-Validation Accuracy'].idxmax()]
show(df_best)
Feature Extraction Model Cross-Validation Accuracy Test Accuracy
Loading ITables v2.2.3 from the internet... (need help?)
Code
fig = go.Figure()

fig.add_trace(
    go.Bar(
        x=best_combination_per_feature['Feature Extraction'],
        y=best_combination_per_feature['Cross-Validation Accuracy'],
        marker=dict(
            colorscale='Viridis',
            color=best_combination_per_feature['Cross-Validation Accuracy'],
            colorbar=dict(title="Cross-Validation Accuracy"),
            showscale=True
        ),
        text=best_combination_per_feature['Model'],
        name="Feature Extraction",
        hoverinfo='x+text+y',
    )
)

fig.update_layout(
    xaxis_title="Feature Extraction",
    yaxis_title="Cross-Validation Accuracy"
)

fig.show()

7.2 Indicadores de los resultados

Code
df_results = pd.DataFrame(results)
df_results.to_csv("One-to-Many-Results.csv", index=False)
df_ordenado = df_results.sort_values(by='accuracy', ascending=False)
show(df_ordenado)
accuracy precision f1 fpr_weighted fnr_weighted recall_weighted grr model
Loading ITables v2.2.3 from the internet... (need help?)

7.3 Precisión de los clasificadores

Code
fig = go.Figure()
unique_models = df_results['model'].unique()
for name in unique_models:
    model_data = df_results[df_results['model'] == name]

    fig.add_trace(
        go.Scatter(
            x=model_data.index + 1,
            y=model_data['accuracy'],
            mode="lines+markers",
            name=name,
        )
    )

fig.update_layout(
    title="Comparación de Accuracy entre Clasificadores",
    xaxis_title="Número de Prueba",
    yaxis_title="Accuracy",
    template="plotly_white",
)

fig.show()

7.4 Comparación con el estado del arte

Code
mejor_modelo = df_results.loc[df_results['accuracy'].idxmax()]
models_accuracies = {
    "[1]": .98,
    "[2] m": .96,
    "[2] s": .9073,
    "[3]": .935,
    "[4]": .921,
    "[5]": .949,
    f"Ours ({mejor_modelo['model']})": mejor_modelo['accuracy'],
}

models = list(models_accuracies.keys())
accuracies = list(models_accuracies.values())

fig = go.Figure(data=[
    go.Scatter(
        x=models,
        y=accuracies,
        mode='markers+lines',
        marker=dict(size=10, color=accuracies, colorscale='Viridis', showscale=True),
        line=dict(dash='solid'),
        name='Accuracy'
    )
])

fig.update_layout(
    title="Model Accuracies",
    xaxis_title="Models",
    yaxis_title="Accuracy",
    yaxis=dict(range=[0.9, 1.0]),
    template="plotly_white"
)

fig.show()